package com.agile.leetcode.rpc.server;

import cn.hutool.json.JSONUtil;
import com.agile.leetcode.rpc.pojo.CalculatorRpcRequest;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Objects;

/**
 * @Author KD
 * @Date 2021/1/20 14:08
 */
@SuppressWarnings("all")
public class NioCalculateServer {
    /**
     * 端口号
     */
    private static final int PORT = 7001;
    /**
     * 选择器
     */
    private Selector selector;
    /**
     * 服务器
     */
    private ServerSocketChannel serverSocketChannel;

    public NioCalculateServer() {
        try {
            // 初始化选择器
            selector = Selector.open();
            // 初始化服务器
            serverSocketChannel = ServerSocketChannel.open();
            // 绑定端口
            serverSocketChannel.bind(new InetSocketAddress(PORT));
            // 配置非阻塞
            serverSocketChannel.configureBlocking(false);

            // 注册到选择器
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听
     */
    public void listen() {
        try {
            while (true) {
                // 查看是否有连接
                int i = selector.select();
                if (i > 0) {
                    // 拿到事件
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        // 拿到该事件
                        SelectionKey key = iterator.next();
                        // 是否是连接事件
                        if (key.isAcceptable()) {
                            // 接收
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            // 将其配置成非阻塞
                            socketChannel.configureBlocking(false);
                            // 注册到selector
                            socketChannel.register(selector, SelectionKey.OP_READ,ByteBuffer.allocate(1024));
                            // 输出状态
                            System.out.println(socketChannel.getRemoteAddress() + "连接了");
                        }
                        if (key.isReadable()) {
                            System.out.println("进入读处理了");
                            // 读取事件
                            // 拿到通道
                            SocketChannel channel = (SocketChannel) key.channel();
                            //
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            // 读取数据
                            int len = 0;
                            String json = "";
                            if (len != -1) {
                                len = channel.read(buffer);
                                json = json + new String(buffer.array());
                                // 清除
                                buffer.clear();
                            }
                            System.out.println(json);
                            // 执行方法
                            CalculatorRpcRequest calculatorRpcRequest = JSONUtil.toBean(json, CalculatorRpcRequest.class);
                            // 拿到
                            int b = calculatorRpcRequest.getB();
                            int a = calculatorRpcRequest.getA();
                            String method = calculatorRpcRequest.getMethod();
                            RemoteCanculateImpl remoteCanculate = new RemoteCanculateImpl();
                            Class<? extends RemoteCanculateImpl> clazz = remoteCanculate.getClass();
                            Method[] methods = clazz.getMethods();
                            for (Method method1 : methods) {
                                if (Objects.equals(method1.getName(), method)) {
                                    Object invoke = method1.invoke(remoteCanculate, a, b);
                                    // 写回数据
                                    System.out.println(invoke);
                                    channel.write(ByteBuffer.wrap((invoke+"").getBytes()));
                                }
                            }
                        }
                        iterator.remove();
                    }
                } else {
                    System.out.println("等待连接");
                }
            }
        } catch (Exception ex) {

        }
    }

    public static void main(String[] args) {
        NioCalculateServer server = new NioCalculateServer();
        server.listen();
    }
}
